package com.sbsj.config.shiro;

import com.sbsj.constants.CommonConstant;
import com.sbsj.models.TAccount;
import com.sbsj.models.TResources;
import com.sbsj.models.TRole;
import com.sbsj.service.AccountService;
import com.sbsj.service.ResourcesService;
import com.sbsj.service.RoleService;
import com.sbsj.utils.JedisUtil;
import com.sbsj.utils.JwtUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

public class ShiroRealm extends AuthorizingRealm {

    private static final Logger LOGGER = LogManager.getLogger(ShiroRealm.class);

    @Autowired
    private AccountService accountService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private ResourcesService resourcesService;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        TAccount account = (TAccount)getAvailablePrincipal(principalCollection);
        String username = JwtUtil.getClaim(principalCollection.toString(),CommonConstant.ACCOUNT.getValue().toString());
        List<TRole> roleDtos = roleService.findRoleByUser(account.getId());
        for(TRole role : roleDtos)
        {
            if(role != null)
            {
                // 添加角色
                simpleAuthorizationInfo.addRole(role.getName());
                // 根据用户角色查询权限
                List<TResources> permissionDtos = resourcesService.findResourcesByRoleId(role.getId());
                for (TResources resources : permissionDtos) {
                    if (resources != null) {
                        // 添加权限
                        simpleAuthorizationInfo.addStringPermission(resources.getName());
                    }
                }
            }
        }
        return simpleAuthorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String token = (String) authenticationToken.getCredentials();
        String username = JwtUtil.getClaim(token, CommonConstant.ACCOUNT.getValue().toString());
        if (StringUtils.isEmpty(username)) {
            throw new AuthenticationException("token非法无效!");
        }
        TAccount account = accountService.selectAccountOne(username);
        if (account == null)
        {
            throw new AuthenticationException("用户名或密码无效");
        }
        // 开始认证，要AccessToken认证通过，且Redis中存在RefreshToken，且两个Token时间戳一致
        if (JwtUtil.verify(token,username,account.getPassword()) &&
                JedisUtil.exists(CommonConstant.PREFIX_SHIRO_REFRESH_TOKEN.getValue().toString() + account)) {
            String currentTimeMillisRedis = JedisUtil.getObject(CommonConstant.PREFIX_SHIRO_REFRESH_TOKEN.getValue().toString() + account).toString();
            // 获取AccessToken时间戳，与RefreshToken的时间戳对比
            if (JwtUtil.getClaim(token, CommonConstant.CURRENT_TIME_MILLIS.getValue().toString()).equals(currentTimeMillisRedis)) {
                return new SimpleAuthenticationInfo(token, token, "userRealm");
            }
        }
        throw new AuthenticationException("Token已过期(Token expired or incorrect.)");
    }
}
